<?php
/**
 * Zendex (Zend (Framework) Extensions)
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://zfx.netatoo.fr/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to support@netatoo.fr so we can send you a copy immediately.
 *
 * @category   Zendex
 * @package    Zendex_Bootstrap
 * @copyright  Copyright (c) 2007 Netatoo FR S.A.R.L. (http://www.netatoo.fr)
 * @license    http://Zendex.netatoo.fr/license/new-bsd     New BSD License
 */

/**
 * @see Zendex_Setup
 */
require_once 'Zendex/Setup.php';

/**
 * @see Zendex_Bootstrap_Exception
 */
require_once 'Zendex/Bootstrap/Exception.php';

/**
 * @see Zendex_Bootstrap_Dispatcher_Abstract
 */
require_once 'Zendex/Bootstrap/Dispatcher/Abstract.php';

/**
 * @see Zendex_Bootstrap_Plugin_Broker
 */
require_once 'Zendex/Bootstrap/Plugin/Broker.php';


/**
 * @category   Zendex
 * @package    Zendex_Bootstrap
 * @copyright  Copyright (c) 2007 Netatoo FR S.A.R.L. (http://www.netatoo.fr)
 * @license    http://Zendex.netatoo.fr/license/new-bsd     New BSD License
 */
class Zendex_Bootstrap extends Zendex_Bootstrap_Dispatcher_Abstract
{    
    /**
     * Retrieve self instance. 
     * Marked only as protected to allow extension of the class.
     * 
     * @var Zendex_Setup_Bootstrap
     */
    protected static $_instance = null;

    /**
     * Contain global xml document
     * 
     * @var SimpleXMLElement
     */
    private static $_xmlDocument = null;
    
    /**
     * Instance of Zendex_Bootstrap_Plugin_Broker
     * 
     * @var Zendex_Bootstrap_Plugin_Broker
     */
    private static $_plugins = array();
    
    /**
     * Contain within array, list of parser's instance
     * 
     * @var array
     */
    private static $_dispatchers = array();
    
    /**
     * Constructor
     *
     * Instantiate using {@link getInstance()}; setup bootstrap is a singleton
     * object.
     *
     * As protected for extensions. 
     *
     * @return void
     */
    protected function __construct()
    {
        self::$_plugins = new Zendex_Bootstrap_Plugin_Broker();
    }

    /**
     * Enforce singleton; disallow cloning 
     * 
     * @return void
     */
    private function __clone()
    {
        throw new Zendex_Bootstrap_Exception("You cannot clone this object!");
    }

    /**
     * Singleton instance
     *
     * @param string $filename
     * @return Zendex_Setup_Bootstrap
     */
    public static function launch($filename)
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
            self::$_instance->_launchParser($filename);
        }

        return self::$_instance;
    }

    /**
     * Set xml document
     *
     * @param string/SimpleXMLElement $xml
     */
    public function setXmlDocument($xml) 
    {
        if(is_string($xml)) {
            self::$_xmlDocument = simplexml_load_string($xml);
        } else {
            self::$_xmlDocument = $xml;
        }
    }
    
    /**
     * Get xml document
     *
     * @return SimpleXMLElement
     */
    public function getXmlDocument() 
    {
        return self::$_xmlDocument;
    }
    
       /**
     * Initalize the application setup.
     * Launch recursive parser.
     * 
     * @param string $filename
     * @return void
     */
    private function _launchParser($filename) 
    {
        if (empty($filename)) {
            throw new Zendex_Bootstrap_Exception('Filename is not set');
        }

        self::setXmlDocument(simplexml_load_file($filename));
        
        /**
         * Load and register required plugin class
         * Load and instanciate required parser class
         */
        $this->_loadPlugin();
        $this->_loadDispatcher();
        
        self::$_plugins->launchStartup();
        
        /**
         * Start parsing of XML file
         */
        $this->_dispatch(self::$_xmlDocument);
        
        Zend_Debug::dump(self::$_xmlDocument->asXml());
    }
    
    /**
     * Load an parser class.
     * 
     * @param string $name
     * @return void
     */
    private function _loadPlugin() 
    {
        $document = $this->getXmlDocument();
        
        if(isset($document->LoadPlugin)) {
            
            foreach($document->LoadPlugin as $plugin) { 
                
                if(is_null($plugin['className'])) {
                    continue;
                }
                
                $name = (string) $plugin['className'];

                /** @see Zend_Loader */
                require_once 'Zend/Loader.php';
                
                $className = 'Zendex_Bootstrap_Plugin_' . $name;
                Zend_Loader::loadClass($className);
                
                /** Instanciate the parser and recover it */
                $plugin = new $className();
                self::$_plugins->registerPlugin($plugin);
            }
        }
        
    }
    
    /**
     * Load dispatcher classes.
     * 
     * @param string $name
     * @return void
     */
    private function _loadDispatcher() 
    {
        $document = $this->getXmlDocument();
        
        if(isset($document->LoadDispatcher)) {
            
            foreach($document->LoadDispatcher as $dispatcher) { 
                
                if(is_null($dispatcher['className'])) {
                    continue;
                }
                
                $name = (string) $dispatcher['className'];

                /** @see Zend_Loader */
                require_once 'Zend/Loader.php';
                
                $className = 'Zendex_Bootstrap_Dispatcher_' . $name;
                Zend_Loader::loadClass($className);
                
                /** Instanciate the parser and recover it */
                $dispatcher = new $className();
                self::$_dispatchers[$name] = $dispatcher;
            }
        }
        
    }
    
    /**
     * Retrieve the loaded dispatcher on associative array (see self::$_dispatchers)
     * 
     * @return array
     */
    public static function getDispatchers() 
    {
        return self::$_dispatchers;
    }
    
    /**
     * Retrieve the loaded parser on associative array (see self::$_loadedParser)
     * 
     * @return array
     */
    public static function getPlugins() 
    {
        return self::$_plugins;
    }
 
}